#pragma once
#include "Event.h"
#include "WorkerThread.h"
#include "ThreadPool.h"

bool IsInRenderingThread();
class FRenderCommand
{
public:
	static BattleFire::ENamedThreads GetDesiredThread()
	{
		return BattleFire::GetRenderThread();
	}

	static BattleFire::ESubsequentsMode GetSubsequentsMode()
	{
		return BattleFire::ESubsequentsMode::FireAndForget;
	}
};
template<typename CommandName, typename LAMBDA>
class TEnqueueUniqueRenderCommandType : public FRenderCommand
{
public:
	TEnqueueUniqueRenderCommandType(LAMBDA&& InLambda) : Lambda(std::forward<LAMBDA>(InLambda)) {}

	void DoTask(BattleFire::ENamedThreads CurrentThread, const BattleFire::RunnableTaskEventRef& MyCompletionGraphEvent)
	{
		Lambda();
	}
private:
	LAMBDA Lambda;
};

template<typename CommandName, typename LAMBDA>
FORCEINLINE void EnqueueUniqueRenderCommand(LAMBDA&& Lambda)
{
	typedef TEnqueueUniqueRenderCommandType<CommandName, LAMBDA> EURCType;
	if (IsInRenderingThread())
	{
		Lambda();
	}
	else
	{
		BattleFire::TRunnableTask<EURCType>::CreateTask().ConstructAndDispatchWhenReady(std::forward<LAMBDA>(Lambda));
	}
}

#define ENQUEUE_RENDER_COMMAND(Type) \
	struct Type##Name \
	{  \
		static const char* cstr() { return #Type; } \
	}; \
	EnqueueUniqueRenderCommand<Type##Name>

template<typename LAMBDA>
FORCEINLINE void EnqueueUniqueRenderCommand(LAMBDA& Lambda)
{
	static_assert(sizeof(LAMBDA) == 0, "EnqueueUniqueRenderCommand enforces use of rvalue and therefore move to avoid an extra copy of the Lambda");
}

namespace BattleFire
{
    class RenderingThreadBody : public ThreadBody
    {
	public:
		BattleFireEvent* ReadyEvent;
		RenderingThreadBody()
		{
			ReadyEvent = new BattleFireEvent;
		}
		virtual ~RenderingThreadBody()
		{
			ReadyEvent = nullptr;
		}
		virtual bool Init(void) override;

		virtual void Exit(void) override
		{
			WorkerThread::RenderThreadID = 0;
		}

		virtual uint32 Run(void) override;
    };
	void StartRenderingThread();
	void StopRenderingThread();
}
